package core

import (
	"context"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"sync"

	"gitee.com/shijingzhao/go-frame/zcrontab"
	"gitee.com/shijingzhao/go-frame/zhttp"
	"gitee.com/shijingzhao/go-frame/zlog"
	"gitee.com/shijingzhao/go-frame/zrpc"
	"gitee.com/shijingzhao/go-frame/zscript"
)

type App struct {
	config Config

	name   string
	wg     *sync.WaitGroup    // 同步等待
	ctx    context.Context    // 上下文
	cancel context.CancelFunc // 上下文取消

	rpc     *zrpc.Server
	http    *zhttp.Server
	script  *zscript.Server
	crontab *zcrontab.Crontab

	readyFunc  func() // 启动前
	unloadFunc func() // 停止前
}

func NewApp() *App {
	app := new(App)

	app.onLoad()

	app.wg = &sync.WaitGroup{}
	app.config = AppConfig.App

	// 上下文, 上下文取消
	app.ctx, app.cancel = context.WithCancel(
		context.Background(),
	)

	// pprof
	app.StartPprof()

	app.RegRpc()
	app.RegHttp()
	app.RegScript()
	app.RegCrontab()

	return app
}

// onLoad 加载时
func (app *App) onLoad() {
	// 解析配置
	if err := ParseJsonConfigFile(AppConfigFile, &AppConfig); err != nil {
		panic(fmt.Sprintf("[配置文件错误] %s", err.Error()))
	}

	// 日志
	zlog.Init(AppConfig.Log)
}

// OnLoad 加载时
func (app *App) OnLoad(fun func()) *App {
	fun()
	return app
}

// OnReady 启动前
func (app *App) OnReady(fun func()) *App {
	app.readyFunc = fun
	return app
}

// OnUnload 停止前
func (app *App) OnUnload(fun func()) *App {
	app.unloadFunc = fun
	return app
}

// StartPprof 启动net/http/pprof
func (app *App) StartPprof() {
	if len(app.config.Pprof) > 0 {
		go func() {
			_ = http.ListenAndServe(app.config.Pprof, nil)
		}()
	}
}

// RegRpc 注册RPC服务
func (app *App) RegRpc() {
	if len(AppConfig.RpcSer.Addr) != 0 {
		app.rpc = zrpc.NewServer(app.ctx, AppConfig.RpcSer)
	}
}

// AddRpcHandler 添加Rpc方法
func (app *App) AddRpcHandler(handlers []zrpc.Handler) {
	app.rpc.AddHandler(handlers)
}

// AddMiddlewareRpcHandler 添加带中间件的Rpc方法
func (app *App) AddMiddlewareRpcHandler(middlewares []zrpc.Middleware, handlers []zrpc.Handler) {
	app.rpc.AddMiddlewareHandler(middlewares, handlers)
}

// RegHttp 注册HTTP服务
func (app *App) RegHttp() {
	if len(AppConfig.HttpSer.Addr) != 0 {
		app.http = zhttp.NewServer(app.ctx, AppConfig.HttpSer)
	}
}

// AddHttpRoutes 添加Http路由
func (app *App) AddHttpRoutes(routes []zhttp.Route) {
	app.http.AddRoute(routes)
}

// AddMiddlewareHttpRoute 添加带中间件的Http路由
func (app *App) AddMiddlewareHttpRoute(middlewares []zhttp.Middleware, routes []zhttp.Route) {
	app.http.AddMiddlewareRoute(middlewares, routes)
}

// RegScript 注册脚本
func (app *App) RegScript() {
	app.script = zscript.New(app.ctx, AppConfig.ScriptSer)
}

// AddScriptHandler 添加脚本方法
func (app *App) AddScriptHandler(handlers []zscript.Handler) {
	app.script.AddHandler(handlers)
}

// RegCrontab 注册定时任务
func (app *App) RegCrontab() {
	app.crontab = zcrontab.New(app.ctx, AppConfig.CrontabSer)
}

// AddCrontabHandler 添加定时任务
func (app *App) AddCrontabHandler(handlers []zcrontab.Handler) {
	app.crontab.AddHandler(handlers)
}

// regStop 停止流程
func (app *App) regStop() {
	app.wg.Add(1)

	fun := func() {
		defer app.wg.Done()

		if app.unloadFunc != nil {
			app.unloadFunc()
		}

		if app.http != nil {
			app.http.Close()
		}
		if app.rpc != nil {
			app.rpc.Close()
		}
		if app.crontab != nil {
			app.crontab.Stop()
		}

		// 取消上下文
		app.cancel()
	}

	regExitListen(fun)
}

// Run 运行
func (app *App) Run() {
	// 启动前准备
	if app.readyFunc != nil {
		app.readyFunc()
	}
	// 注册停止流程
	app.regStop()

	if app.http != nil {
		app.http.Start(app.wg)
	}

	if app.rpc != nil {
		app.rpc.Start(app.wg)
	}

	if app.script != nil {
		app.script.Start(app.wg)
	}

	if app.crontab != nil {
		app.crontab.Start()
	}

	app.wg.Wait()
}
